use std::sync::Arc;

use axum::Json;
use serde::Serialize;

use crate::{AppState, Error};

pub fn log_error(handler_name: &str) -> Box<dyn Fn(Error) -> Error> {
    let handler_name = handler_name.to_string();
    Box::new(move |err| {
        tracing::error!("👉 [{}] - {:?}", handler_name, err);
        err
    })
}

pub fn get_conn(state: &AppState) -> Arc<sqlx::PgPool> {
    state.pool.clone()
}

#[derive(Serialize, Debug)]
pub struct Response<T> {
    pub code: i32,
    pub msg: String,
    // #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<T>,
}

impl<T: Serialize> Response<T> {
    pub fn new(code: i32, msg: &str, data: Option<T>) -> Self {
        let msg = msg.to_string();
        Self { code, msg, data }
    }

    pub fn ok(data: T) -> Self {
        Self::new(0, "OK", Some(data))
    }

    pub fn to_json(self) -> Json<Response<T>> {
        Json(self)
    }
}

impl Response<()> {
    pub fn err(e: Error) -> Self {
        Self {
            code: e.code(),
            msg: e.message(),
            data: None,
        }
    }

    pub fn ok_empty() -> Self {
        Self::ok(())
    }
}

#[derive(Serialize)]
pub struct IDResponse {
    pub id: String,
}

#[derive(Serialize)]
pub struct AffResponse {
    pub rows: u64,
}
#[derive(Serialize)]
pub struct BoolResponse {
    pub result: bool,
}
#[derive(Serialize)]
pub struct AddUrlResponse {
    pub url: String,
}
